/*
 *  RingerFSClientServer.cpp
 *  MetaThrift
 *
 *  Created by Ian Pye on 3/25/08.
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
 *
 */

// Thrift
#include <protocol/TBinaryProtocol.h>
#include <server/TSimpleServer.h>
#include <transport/TServerSocket.h>
#include <transport/TTransportUtils.h>
#include <transport/TSocket.h>
#include <transport/TTransportUtils.h>


// Loggers
#include <log4cxx/logger.h>
#include <log4cxx/basicconfigurator.h>
#include <log4cxx/helpers/exception.h>
#include <log4cxx/propertyconfigurator.h>

// Std lib
#include <iostream>
#include <fstream>

#include "Ringer.h"
#include "RingerMetaServer.h"
#include "RingerFS.h"
#include "FileUtil.h"
#include "NetworkUtil.h"
#include "RingerFSClientServer.h"

using namespace std;

using namespace ringer;
using namespace boost;

using namespace facebook::thrift;
using namespace facebook::thrift::protocol;
using namespace facebook::thrift::transport;
using namespace facebook::thrift::server;


RingerFSClientServerHandler::RingerFSClientServerHandler(){}
RingerFSClientServerHandler::~RingerFSClientServerHandler(){}

/**
 Don't be fooled by the name -- this is a request to send the asked for block back to the askee.
 */
void 
RingerFSClientServerHandler::get_block(RingerBlock& _return, const rpath_t& path, const UserInfo& userInfo, const int32_t offset, const int32_t length ){
  
  // Localize the file path
  string local_path;
  LocalizeRingerPath(path.c_str(), local_path);
  
  // Find out if the specified file actually exists
  if (!IsFileInLocalCache(local_path.c_str())){
    InvalidOperation e_not_found = InvalidOperation();
    e_not_found.what = RNOODE_NOT_FOUND;
    e_not_found.why = "I could not find the file matching the path " + path;
    throw e_not_found;
  }     
  // Find out if the user can actually have the specified file
  if (!can_read(path, userInfo)){
    InvalidOperation e_not_allowed = InvalidOperation();
    e_not_allowed.what = RNOODE_NOT_ALLOWED;
    e_not_allowed.why = "You cannot have the write token for " + path;
    throw e_not_allowed;
  }    
  ReadLocalBlock(_return, local_path, offset, length);
}

/**
 @TODO -- Warning -- this currently does not work.
 @TODO -- Take out hard coding of data.
 Another way to transport data. This is like get_block, but functions asyncrounusly.
 */
void RingerFSClientServerHandler::send_block(const UserInfo& userInfo, const rpath_t& path, const int32_t offset, const int32_t length){
  
  // First, get the info, or fail if there is an error
  RingerBlock ret;
  string lpath; 
  LocalizeRingerPath(path.c_str(), lpath);
  try{
    // ReadLocalBlock(ret, lpath, offset, length);
    //get_block(ret, path, userInfo, offset, length);
  } catch (InvalidOperation eio){
    LOG4CXX_INFO(g_logger, "ERROR: " + eio.what);
    return;
  }
  
  LOG4CXX_INFO(g_logger, length);
  LOG4CXX_INFO(g_logger, offset);
  LOG4CXX_INFO(g_logger, "Sending: " + lpath);
  LOG4CXX_INFO(g_logger, "Sending: " + path);
  LOG4CXX_INFO(g_logger, "Sending: " + ret.block_value);

  ret.block_value = "TAKE THIS OUT OF FSClientServer.cpp\n";
  ret.block_size =  ret.block_value.length() + 1;
  
  // Assume now that we have the block needed, and send it off -- To the next method!
 // shared_ptr<TTransport> transport;
 // shared_ptr<RingerMetaServerClient> peer_client;

 // RINGER_GET_CLIENT(userInfo.host.host_name, userInfo.host.host_port, 
   //   transport, peer_client);
  try {
   // transport->open();
   // peer_client->accept_block(ret, path, offset, length, userInfo);
  //  transport->close();
  } catch (TException &tx) {
    LOG4CXX_INFO(g_logger, string("ERROR: ") + tx.what());
  }
}

void RingerFSClientServerHandler::accept_block(const RingerBlock& ret_val, const rpath_t& path, const int32_t offset, const int32_t length, const UserInfo& userInfo){
  
  // Localize the file path
  string local_path;
  LocalizeRingerPath(path.c_str(), local_path);
    
  // Find out if the user can actually have the specified file
  if (!can_write(path, userInfo)){
    return;
  }   
    
  WriteReturnValueToDisk(local_path, ret_val, offset);
}

// The rest
int32_t RingerFSClientServerHandler::ping(){return RINGER_PING_RESULT;}
int32_t RingerFSClientServerHandler::add(const int32_t num1, const int32_t num2){ return num1 + num2; }
void RingerFSClientServerHandler::get(RNode& _return, const rpath_t& path, const UserInfo& userInfo){}
void RingerFSClientServerHandler::put(const RNode& node, const UserInfo& userInfo){}
void RingerFSClientServerHandler::remove(const rpath_t& path, const UserInfo& userInfo){}
bool RingerFSClientServerHandler::get_read(const rpath_t& path, const UserInfo& userInfo){return false;}
void RingerFSClientServerHandler::end_read(const rpath_t& path, const UserInfo& userInfo){}
bool RingerFSClientServerHandler::get_write(const rpath_t& path, const UserInfo& userInfo){return false;}
void RingerFSClientServerHandler::end_write(const rpath_t& path, const UserInfo& userInfo){}
// Tell us we have a kid.
void RingerFSClientServerHandler::connect_parent(const host_t& child_info){}
// Tell us the kid is going away.
void RingerFSClientServerHandler::disconnect_parent(const host_t& child_info){}
// Returns the owner info for the given path.
void RingerFSClientServerHandler::get_mds_owner(host_t& _return, const rpath_t& path){}
// takes word of an rnode being added below.
void RingerFSClientServerHandler::alert_parent_of_rnode(const rpath_t& path, const host_t& owner_info){}
void RingerFSClientServerHandler::alert_parent_of_removed_rnode(const rpath_t& path){}


